#include "check.h"
#include <iomanip>
#include <sstream>

// URL解码函数
string url_decode(const string& str) {
    string decoded;
    size_t len = str.length();
    for (size_t i = 0; i < len; ++i) {
        if (str[i] == '%' && i + 2 < len) {
            string hex = str.substr(i + 1, 2);
            char c = static_cast<char>(strtol(hex.c_str(), nullptr, 16));
            decoded += c;
            i += 2;
        } else if (str[i] == '+') {
            decoded += ' '; // '+' 转换为空格
        } else {
            decoded += str[i];
        }
    }
    return decoded;
}

string check(const HttpRequest& http) {
    set<string> attacks;
    HttpRequest::Method method = http.get_method();
    if (find(ALLOWED_METHODS.begin(), ALLOWED_METHODS.end(), method) == ALLOWED_METHODS.end()) {
        attacks.insert("Illegal Http method");
    }

    // 获取请求各部分
    string url = http.get_url();
    string query = http.get_query();
    string body = http.get_body();
    auto headers = http.get_headers();
    cout << "Checking request: " << url << endl;
    cout << "Query: " << query << endl;
    cout << "Body: " << body << endl;
    cout << "Headers:";
    for (const auto& [key, value] : headers) {
        cout << key << ": " << value << endl;
    }
    cout << "Headers end" << endl; 

        // URL解码
    string decoded_url = url_decode(url);
    string decoded_query = url_decode(query);

    // 调试输出解码后的URL和Query
    cout << "原始URL: " << url << endl;
    cout << "解码后的URL: " << decoded_url << endl;
    cout << "原始Query: " << query << endl;
    cout << "解码后的Query: " << decoded_query << endl;

    // 定义检测函数
    auto detect_attacks = [&](const string& content, const string& context) {
        // 路径遍历检测
        for (const auto& pattern : TRAVERSAL_PATTERNS) {
            regex re(pattern, regex_constants::icase);
            if (regex_search(content, re)) {
                attacks.insert("Path traversal attack in " + context);
                break;
            }
        }

        // SQL注入检测
        for (const auto& pattern : SQL_KEYWORDS) {
            regex re(pattern, regex_constants::icase);
            if (regex_search(content, re)) {
                attacks.insert("SQL injection in " + context);
                break;
            }
        }

        // XSS攻击检测
        for (const auto& pattern : XSS_PATTERNS) {
            regex re(pattern, regex_constants::icase);
            if (regex_search(content, re)) {
                attacks.insert("XSS attack in " + context);
                break;
            }
        }

        // 命令注入检测
        for (const auto& pattern : CMD_CHARS) {
            regex re(pattern);
            if (regex_search(content, re)) {
                attacks.insert("Command injection in " + context);
                break;
            }
        }
    };

    // 检测解码后的URL和查询参数
    detect_attacks(decoded_url, "URL");
    detect_attacks(decoded_query, "query");

    // 开放重定向检测
    for (const auto& pattern : OPEN_REDIRECT_PATTERNS) {
        regex re(pattern, regex_constants::icase);
        if (regex_search(query, re)) {
            attacks.insert("Open redirect attempt");
            break;
        }
    }

    // 方法覆盖攻击
    if (headers.find("X-HTTP-Method-Override") != headers.end()) {
        attacks.insert("HTTP method override");
    }

    // 请求头注入攻击
    for (const auto& [header_name, header_value] : headers) {
        string lower_header = header_name;
        transform(lower_header.begin(), lower_header.end(), lower_header.begin(), ::tolower);
        
        // 跳过对 "accept" 请求头的检测
        if (lower_header == "accept") {
            continue;
        }

        for (const auto& pattern : SQL_KEYWORDS) {
            regex re(pattern, regex_constants::icase);
            if (regex_search(header_value, re)) {
                attacks.insert("Header injection: " + header_name);
                cout << "检测到头部注入攻击，头部名称: " << header_name << ", 值: " << header_value << endl;
                break;
            }
        }
        for (const auto& pattern : XSS_PATTERNS) {
            regex re(pattern, regex_constants::icase);
            if (regex_search(header_value, re)) {
                attacks.insert("Header injection: " + header_name);
                cout << "检测到头部注入攻击，头部名称: " << header_name << ", 值: " << header_value << endl;
                break;
            }
        }

        // 异常HTTP头检测
        regex header_name_re(R"([^\x20-\x7E])");
        if (regex_search(header_name, header_name_re)) {
            attacks.insert("Malformed header name: " + header_name);
        }
    }

    // 缺失安全头检测
    static const set<string> SECURITY_HEADERS = {
        "X-Content-Type-Options", "X-Frame-Options"
    };
    for (const auto& header : SECURITY_HEADERS) {
        if (headers.find(header) == headers.end()) {
            cout << "Warning: Missing " << header << " header" << endl;
        }
    }

    // 请求体检测
    if (!body.empty()) {
        detect_attacks(body, "body");

        // XXE攻击检测
        auto it_ct = headers.find("Content-Type");
        if (it_ct != headers.end() && 
            (it_ct->second.find("application/xml") != string::npos || 
             it_ct->second.find("text/xml") != string::npos)) {
            for (const auto& pattern : XXE_PATTERNS) {
                regex re(pattern, regex_constants::icase);
                if (regex_search(body, re)) {
                    attacks.insert("XXE attack");
                    break;
                }
            }
        }

        // SSRF攻击检测
        for (const auto& pattern : SSRF_PATTERNS) {
            regex re(pattern, regex_constants::icase);
            if (regex_search(body, re)) {
                attacks.insert("SSRF attempt");
                break;
            }
        }

        // 敏感信息泄露检测
        for (const auto& param : SENSITIVE_PARAMS) {
            regex re("\\b" + param + "\\s*=[^&]+", regex_constants::icase);
            if (regex_search(body, re)) {
                attacks.insert("Sensitive parameter in body: " + param);
            }
        }

        // JSON格式的CSRF令牌检测
        if (it_ct != headers.end() && 
            it_ct->second.find("application/json") != string::npos &&
            (method == HttpRequest::Method::POST || method == HttpRequest::Method::PUT || method == HttpRequest::Method::DELETE)) {
            regex csrf_re(R"(\b(?:csrf|xsrf)\b)", regex_constants::icase);
            if (!regex_search(body, csrf_re)) {
                attacks.insert("Missing CSRF token in JSON body");
            }
        }
    }

    // HTTP参数污染检测
    auto parse_params = [](const string& str) -> map<string, vector<string>> {
        map<string, vector<string>> params;
        istringstream iss(str);
        string pair;
        while (getline(iss, pair, '&')) {
            size_t pos = pair.find('=');
            if (pos != string::npos) {
                string key = pair.substr(0, pos);
                string value = pair.substr(pos + 1);
                params[key].push_back(value);
            }
        }
        return params;
    };

    auto query_params = parse_params(query);
    for (const auto& [key, values] : query_params) {
        if (values.size() > 1) {
            attacks.insert("Parameter pollution: " + key);
        }
    }

    // 表单格式的CSRF令牌检测
    if (method == HttpRequest::Method::POST && 
        headers.find("Content-Type") != headers.end() && 
        headers["Content-Type"].find("application/x-www-form-urlencoded") != string::npos) {
        auto body_params = parse_params(body);
        static const set<string> SENSITIVE_KEYS = {
            "password", "email", "username", "delete", "transfer", "payment"
        };
        
        bool is_sensitive_form = any_of(body_params.begin(), body_params.end(),
            [](const auto& param) { return SENSITIVE_KEYS.count(param.first); });
        
        if (is_sensitive_form &&
            body_params.find("csrf_token") == body_params.end() &&
            body_params.find("csrf-token") == body_params.end() &&
            body_params.find("_csrf") == body_params.end()) {
            attacks.insert("Missing CSRF token in sensitive form");
        }
    }

    return attacks.empty() ? "1" : [&]() {
        string result;
        for (auto it = attacks.begin(); it != attacks.end(); ++it) {
            if (it != attacks.begin()) result += ",";
            result += *it;
        }
        return result;
    }();
}